#include <iostream>
#include <netinet/in.h>
#include <string.h>

extern "C" {
#include <eXosip2/eXosip.h>

}

int main() {
    eXosip_event_t *je = NULL;
    osip_message_t *ack = NULL;
    osip_message_t *invite = NULL;
    osip_message_t *answer = NULL;
    sdp_message_t *remote_sdp = NULL;
    int call_id, dialog_id;
    int i, j;
    int id;
    const char *sour_call = "sip:140@192.168.0.115";
    const char *dest_call = "sip:133@192.168.0.115:15060";//client ip
    char command;
    char tmp[4096];
    char localip[128];
    int pos = 0;
    //初始化sip
    struct eXosip_t *excontext;
    excontext = eXosip_malloc();
    i = eXosip_init(excontext);
    if (i != 0)
    {
        printf("Can't initialize eXosip!\n");
        return -1;
    }
    else
    {
        printf("eXosip_init successfully!\n");
    }
    i = eXosip_listen_addr(excontext, IPPROTO_UDP, NULL, 15061, AF_INET, 0);
    if (i != 0)
    {
        eXosip_quit(excontext);
        fprintf(stderr, "eXosip_listen_addr error!\nCouldn't initialize transport layer!\n");
    }
    for (;;)
    {
        //侦听是否有消息到来
        je = eXosip_event_wait(excontext, 0, 50);
        //协议栈带有此语句,具体作用未知
        eXosip_lock(excontext);
        eXosip_default_action(excontext, je);
        //eXosip_automatic_refresh();
        eXosip_automatic_action(excontext);
        eXosip_unlock(excontext);
        if (je == NULL)//没有接收到消息
            continue;
        // printf ("the cid is %s, did is %s/n", je->did, je->cid);
        switch (je->type)
        {
            case EXOSIP_MESSAGE_NEW://新的消息到来
                printf(" EXOSIP_MESSAGE_NEW!\n");
                if (MSG_IS_MESSAGE(je->request))//如果接受到的消息类型是MESSAGE
                {
                    {
                        osip_body_t *body;
                        osip_message_get_body(je->request, 0, &body);
                        printf("I get the msg is: %s\n", body->body);
                        //printf ("the cid is %s, did is %s/n", je->did, je->cid);
                    }
                    //按照规则，需要回复OK信息
                    eXosip_message_build_answer(excontext, je->tid, 200, &answer);
                    eXosip_message_send_answer(excontext, je->tid, 200, answer);
                }
                break;
            case EXOSIP_CALL_INVITE:
            {	//得到接收到消息的具体信息
                printf("Received a INVITE msg from %s:%s, UserName is %s, password is %s\n", je->request->req_uri->host,
                       je->request->req_uri->port, je->request->req_uri->username, je->request->req_uri->password);
                //得到消息体,认为该消息就是SDP格式.
                remote_sdp = eXosip_get_remote_sdp(excontext, je->did);
                call_id = je->cid;
                dialog_id = je->did;

                eXosip_lock(excontext);
                eXosip_call_send_answer(excontext, je->tid, 180, NULL);
                i = eXosip_call_build_answer(excontext, je->tid, 200, &answer);
                if (i != 0)
                {
                    printf("This request msg is invalid!Cann't response!\n");
                    eXosip_call_send_answer(excontext, je->tid, 400, NULL);
                }
                else
                {
                    snprintf(tmp, 4096,
                                "v=0\r\n"
                                        "o=anonymous 0 0 IN IP4 0.0.0.0\r\n"
                                        "t=1 10\r\n");

                    //设置回复的SDP消息体,下一步计划分析消息体
                    //没有分析消息体，直接回复原来的消息，这一块做的不好。
                    osip_message_set_body(answer, tmp, strlen(tmp));
                    osip_message_set_content_type(answer, "application/sdp");

                    eXosip_call_send_answer(excontext, je->tid, 200, answer);
                    printf("send 200 over!\n");
                }
                eXosip_unlock(excontext);

                //显示出在sdp消息体中的attribute 的内容,里面计划存放我们的信息
                printf("the INFO is :\n");


                //sdp_media_t *connection = eXosip_get_audio_media(remote_sdp);

                //if (!connection)

                // return false;

                //char*  audio_ip = connection->c_addr; //audio_ip

                sdp_media_t * audio_sdp = eXosip_get_audio_media(remote_sdp);

                if (!audio_sdp)

                    return false;

                char* audio_port = audio_sdp->m_port; //audio_port

                for (int i = 0; i < audio_sdp->a_attributes.nb_elt; i++)

                {
                    sdp_attribute_t *attr = (sdp_attribute_t*)osip_list_get(&audio_sdp->a_attributes, i);
                    printf("%s : %s\n", attr->a_att_field, attr->a_att_value);
                }

                while (!osip_list_eol(&(remote_sdp->a_attributes), pos))
                {
                    sdp_attribute_t *at;

                    at = (sdp_attribute_t *)osip_list_get(&remote_sdp->a_attributes, pos);
                    printf("%s : %s\n", at->a_att_field, at->a_att_value);//这里解释了为什么在SDP消息体中属性a里面存放必须是两列

                    pos++;
                }
                while (!osip_list_eol(&(remote_sdp->m_medias), pos))
                {
                    sdp_attribute_t *at;

                    at = (sdp_attribute_t *)osip_list_get(&remote_sdp->m_medias, pos);
                    printf("%s : %s\n", at->a_att_field, at->a_att_value);//这里解释了为什么在SDP消息体中属性a里面存放必须是两列

                    pos++;
                }
            }
                break;
            case EXOSIP_CALL_ACK:
                printf("ACK recieved!\n");
                // printf ("the cid is %s, did is %s/n", je->did, je->cid);
                break;
            case EXOSIP_CALL_CLOSED:
                printf("the remote hold the session!\n");
                // eXosip_call_build_ack(dialog_id, &ack);
                //eXosip_call_send_ack(dialog_id, ack);
                i = eXosip_call_build_answer(excontext, je->tid, 200, &answer);
                if (i != 0)
                {
                    printf("This request msg is invalid!Cann't response!\n");
                    eXosip_call_send_answer(excontext, je->tid, 400, NULL);

                }
                else
                {
                    eXosip_call_send_answer(excontext, je->tid, 200, answer);
                    printf("bye send 200 over!\n");
                }
                break;
            case EXOSIP_CALL_MESSAGE_NEW://至于该类型和EXOSIP_MESSAGE_NEW的区别，源代码这么解释的
                /*
                // request related events within calls (except INVITE)
                EXOSIP_CALL_MESSAGE_NEW,          < announce new incoming request.
                // response received for request outside calls
                EXOSIP_MESSAGE_NEW,          < announce new incoming request.
                我也不是很明白，理解是：EXOSIP_CALL_MESSAGE_NEW是一个呼叫中的新的消息到来，比如ring trying都算，所以在接受到后必须判断
                该消息类型，EXOSIP_MESSAGE_NEW而是表示不是呼叫内的消息到来。
                该解释有不妥地方，仅供参考。
                */
                printf(" EXOSIP_CALL_MESSAGE_NEW\n");
                if (MSG_IS_INFO(je->request)) //如果传输的是INFO方法
                {
                    eXosip_lock(excontext);
                    i = eXosip_call_build_answer(excontext, je->tid, 200, &answer);
                    if (i == 0)
                    {
                        eXosip_call_send_answer(excontext, je->tid, 200, answer);
                    }
                    eXosip_unlock(excontext);
                    {
                        osip_body_t *body;
                        osip_message_get_body(je->request, 0, &body);
                        printf("the body is %s\n", body->body);
                    }
                }
                break;
            default:
                printf("Could not parse the msg!\n");
        }
    }
}